# include "scene.h"
# include <stdio.h>
# include <math.h>
# include <stdlib.h>

extern char **parse_str(const char *str, char c, unsigned short start, unsigned short end, unsigned short *nsubs);
extern double str2num(const char *str, short nsubs);

static short r_conf_grid(struct grid_config *gc, struct grid *g);
static short th_conf_grid(struct grid_config *gc, struct grid *g);
static short z_conf_grid(struct grid_config *gc, struct grid *g);

# ifndef READ_GRID_FILES
static int nearest_int(double x);
# endif

static short print_grid_conf(const struct grid_config *gc, const struct grid *g);

extern short conf_grid(struct grid_config *gc, struct grid *g)
{
 short e;
#ifdef TRACE_FILE
 fprintf(g->trptr, "Entering into 'conf_grid()'...\n");
#endif

 e = r_conf_grid(gc, g);
 if(e >= 0) e = th_conf_grid(gc, g);
 if(e >= 0) e = z_conf_grid(gc, g);
 if(e >= 0) e = print_grid_conf((const struct grid_config *)gc, (const struct grid *)g);

#ifdef TRACE_FILE
 fprintf(g->trptr, "...'conf_grid()' ends.\n");
#endif

 return e;
}



static short r_conf_grid(struct grid_config *gc, struct grid *g)
{
 double temp;
 unsigned short i, n;
 char *str, **s, fname[MAX_FNAME_LEN+1];
 FILE *ptr;

#ifdef TRACE_FILE
 fprintf(g->trptr, "Entering into 'r_conf_grid()'...\n");
#endif

#ifdef READ_GRID_FILES
/* Opening the r-grid file to load the grids from. */
 sprintf(fname, "%02d.%s.dat", RUN_CNT-1, R_FILE);
 fprintf(g->lptr, "Reading grids from the file '%s'.\n", fname);

 ptr = (FILE *)fopen(fname, "r");

/* Determining the number of char in first-line. */
 for(n = 0; getc(ptr) != '\n'; n++);
 str = (char *)malloc(sizeof(char)*(n+1));
 rewind(ptr);

/* Reading first line of the file to determine number of grids and other grid parameters for various sections. */
 for(i = 0; i < n; i++) str[i] = getc(ptr);
 str[n] = '\0';
 s = parse_str(str, ' ', 1, 4, &n);
 free(str);

 if(n != 4)
     {
      fprintf(g->lptr, "ERROR:: In 'r_conf_grid()': the r-grid file '%s' seems to be currupt.\nExiting...\n", fname);
      exit(-1);
     }

/* Assigning number of grids for various sections. */
 g->nr = (unsigned short)str2num(s[0], 1); free(s[0]);

 g->nr_nozzle = (unsigned short)str2num(s[1], 1); free(s[1]);
 g->nr_gap = (unsigned short)str2num(s[2], 1); free(s[2]);
 if((n = (unsigned short)str2num(s[3], 1)) != NrG)
     {
      fprintf(g->lptr, "ERROR:: In 'r_conf_grid()': In the file '%s', number of ghost cells = %d != NrG = %d.\nExiting...\n", fname, n, NrG);
      exit(-1);
     }

 free(s[3]); free(s); fclose(ptr);

#else

# ifdef r_UNIF_GRID
 fprintf(g->lptr, "Uniform grids are being generated in r-direction.\n");
 fprintf(g->lptr, "ERROR:: in 'r_conf_grid()': No definition for generation of uniform-grids in radial direction.\n");
 return -1;

# else

 fprintf(g->lptr, "Non-uniform grids are being generated in r-direction.\n");

 gc->nr_center = nearest_int(2*r_MID1/(dr_CENTER+dr_MID1));
 gc->r_cd_center = (dr_MID1-dr_CENTER)/(gc->nr_center-1);
 temp = 2*dr_CENTER/gc->r_cd_center - 1;
 g->nr_nozzle = nearest_int(0.5*temp*(sqrt(1+8*r_NOZZLE/(gc->r_cd_center*temp*temp))-1));
 gc->r_cd_center = 2*(r_NOZZLE/g->nr_nozzle - dr_CENTER)/(g->nr_nozzle-1);
 gc->dr_mid1 = dr_CENTER + (gc->nr_center-1)*gc->r_cd_center;
 gc->r_mid1 = 0.5*gc->nr_center*(dr_CENTER+gc->dr_mid1);

 gc->nr_mid12 = nearest_int(2*(r_MID2-gc->r_mid1)/(gc->dr_mid1+dr_MID2));
 gc->r_mid2 = gc->r_mid1 + 0.5*gc->nr_mid12*(gc->dr_mid1+dr_MID2);
 gc->r_cd_mid12 = (dr_MID2-gc->dr_mid1)/(gc->nr_mid12-1);

 gc->nr_base = nearest_int(2*(r_BASE-gc->r_mid2)/(dr_MID2+dr_BASE));
 gc->dr_base = 2*(r_BASE-gc->r_mid2)/gc->nr_base - dr_MID2;
 gc->r_cd_base = (gc->dr_base-dr_MID2)/(gc->nr_base-1);

 g->nr_gap = nearest_int(2*(r_CYL-r_BASE)/(gc->dr_base+dr_WALL));
 gc->dr_wall = 2*(r_CYL-r_BASE)/g->nr_gap - gc->dr_base;
 gc->r_cd_gap = (gc->dr_wall-gc->dr_base)/(g->nr_gap-1);

 g->nr_solid = gc->nr_center - g->nr_nozzle + gc->nr_mid12 + gc->nr_base;
 g->nr = g->nr_nozzle + g->nr_solid + g->nr_gap;

# endif

#endif

#ifdef TRACE_FILE
 fprintf(g->trptr, "...'r_conf_grid()' ends.\n");
#endif

 return 1;
}



static short th_conf_grid(struct grid_config *gc, struct grid *g)
{
 double temp;
 unsigned short i, n;
 char *str, **s, fname[MAX_FNAME_LEN+1];
 FILE *ptr;

#ifdef TRACE_FILE
 fprintf(g->trptr, "Entering into 'th_conf_grid()'...\n");
#endif

#ifdef READ_GRID_FILES
/* Opening the theta-grid file to load the grids from. */
 sprintf(fname, "%02d.%s.dat", RUN_CNT-1, TH_FILE);
 fprintf(g->lptr, "Reading grids from the file '%s'.\n", fname);
 ptr = (FILE *)fopen(fname, "r");

/* Determining the number of char in first-line. */
 for(n = 0; getc(ptr) != '\n'; n++);
 str = (char *)malloc(sizeof(char)*(n+1));
 rewind(ptr);

/* Reading first line of the file to determine number of grids and other grid parameters for various sections. */
 for(i = 0; i < n; i++) str[i] = getc(ptr);
 str[n] = '\0';
 s = parse_str(str, ' ', 1, 2, &n);
 free(str);

 if(n != 2)
     {
      fprintf(g->lptr, "ERROR:: In 'th_conf_grid()': the theta-grid file '%s' seems to be currupt.\nExiting...\n", fname);
      exit(-1);
     }

/* Assigning number of grids for various sections. */
 g->nth = (unsigned short)str2num(s[0], 1);
 free(s[0]);

 if((n = (unsigned short)str2num(s[1], 1)) != NthG)
     {
      fprintf(g->lptr, "ERROR:: In 'th_conf_grid()': In the file '%s', number of ghost cells = %d != NthG = %d.\nExiting...\n", fname, n, NthG);
      exit(-1);
     }

 free(s[1]); free(s); fclose(ptr);

#else

# ifdef th_UNIF_GRID
 fprintf(g->lptr, "Uniform grids are being generated in theta-direction.\n");
 g->nth = (int)((double)360/dTHETA); //Total number of cells in theta direction.


 if(g->nth%2 != 0) fprintf(g->lptr, "No. of cells in theta-direction must be even!!\nIncreasing it by one to nth = %d\n", ++(g->nth));

 temp = (double)360/(double)g->nth; //Re-defining "d_theta": in degrees.
 g->dth = temp*acos(0)/90; //"d_theta" in radians.

 if(nTH_COMP >= 2*NthG+1) g->nth = nTH_COMP; // No. of CELLs chosen for computation keeping in mind symmetry of the problem.
 else{
      fprintf(g->lptr, "ERROR:: in 'th_conf_grid()': Defined number of computational cells = %d. However, it should be more than '%d'. Redefine the parameter 'nTH_COMP' to anything more than '%d', re-compile, and rum the program again. Exiting.\n", nTH_COMP, 2*NthG, 2*NthG);
      exit(1);
     }

# else

 fprintf(g->lptr, "Non-uniform grids are being generated in theta-direction.\n");
 fprintf(g->lptr, "ERROR:: in 'th_conf_grid()': incomplete definition...\n");
 exit(1);
# endif

#endif

#ifdef TRACE_FILE
 fprintf(g->trptr, "...'th_conf_grid()' ends.\n");
#endif
 return 1;
}

 //[Modify both the conf_grid.c and grid_gen.c accordingly]

static short z_conf_grid(struct grid_config *gc, struct grid *g)
{
 unsigned short i, n;
 char *str, **s, fname[MAX_FNAME_LEN+1];
 FILE *ptr;

#ifdef TRACE_FILE
 fprintf(g->trptr, "Entering into 'z_conf_grid()'...\n");
#endif

#ifdef READ_GRID_FILES
/* Opening the z-grid file to load the grids from. */
 sprintf(fname, "%02d.%s.dat", RUN_CNT-1, Z_FILE);
 fprintf(g->lptr, "Reading grids from the file '%s'.\n", fname);
 ptr = (FILE *)fopen(fname, "r");

/* Determining the number of char in first-line. */
 for(n = 0; getc(ptr) != '\n'; n++);
 str = (char *)malloc(sizeof(char)*(n+1));
 rewind(ptr);

/* Reading first line of the file to determine number of grids and other grid parameters for various sections. */
 for(i = 0; i < n; i++) str[i] = getc(ptr);
 str[n] = '\0';
 s = parse_str(str, ' ', 1, 2, &n);
 free(str);

 if(n != 2)
     {
      fprintf(g->lptr, "ERROR:: In 'z_conf_grid()': the z-grid file '%s' seems to be currupt.\nExiting...\n", fname);
      exit(-1);
     }

/* Assigning number of grids for various sections. */
 g->nz = (unsigned short)str2num(s[0], 1); free(s[0]);

 if((n = (unsigned short)str2num(s[1], 1)) != NzG)
     {
      fprintf(g->lptr, "ERROR:: In 'z_conf_grid()': In the file '%s', number of ghost cells = %d != NzG = %d.\nExiting...\n", fname, n, NzG);
      exit(-1);
     }

 free(s[1]); free(s); fclose(ptr);

#else

# ifdef z_UNIF_GRID
 fprintf(g->lptr, "Uniform grids are being generated in z-direction.\n");

 g->nz = (int)(h_CYL/dZ);
 g->dz = h_CYL/g->nz;

# else

 fprintf(g->lptr, "Non-uniform grids are being generated in z-direction.\n");

 gc->nz_top = nearest_int(2*(z_TOP-z_MID2)/(dz_MID2+dz_TOP));
 gc->z_mid2 = z_TOP - 0.5*gc->nz_top*(dz_MID2+dz_TOP);
 gc->z_cd_top = (dz_TOP-dz_MID2)/(gc->nz_top - 1);

 gc->nz_mid12 = nearest_int(2*(gc->z_mid2-z_MID1)/(dz_MID1+dz_MID2));
 gc->z_mid1 = gc->z_mid2 - 0.5*gc->nz_mid12*(dz_MID1+dz_MID2);
 gc->z_cd_mid12 = (dz_MID2-dz_MID1)/(gc->nz_mid12-1);

 gc->nz_mid1 = nearest_int(2*(gc->z_mid1-nz_UNIF_BOT*dz_UNIF_BOT)/(dz_UNIF_BOT+dz_MID1));
 gc->dz_unif_bot = (gc->z_mid1-0.5*gc->nz_mid1*dz_MID1)/(nz_UNIF_BOT+0.5*gc->nz_mid1);
 gc->z_cd_bot = (dz_MID1-gc->dz_unif_bot)/(gc->nz_mid1-1);

 g->nz = nz_UNIF_BOT + gc->nz_mid1 + gc->nz_mid12 + gc->nz_top;
# endif

#endif

#ifdef TRACE_FILE
 fprintf(g->trptr, "...'z_conf_grid()' ends.\n");
#endif

 return 1;
}

# ifndef READ_GRID_FILES
static int nearest_int(double x)
   {
    short flag = 1;

    if(x < 0)
        {
         x = -x;
         flag = -1;
        }

    return flag*((x-(int)x < (int)x+1-x) ? (int)x : (int)x+1);
   }
# endif


static short print_grid_conf(const struct grid_config *gc, const struct grid *g)
  {
   FILE *ptr;

#  ifdef TRACE_FILE
   fprintf(g->trptr, "Entering into 'print_grid_conf()'...\n");
#  endif

   ptr = g->lptr;

#ifdef CHECK_CONFIG
top:
#endif

#ifdef READ_GRID_FILES
   fprintf(ptr, "\n\n['r-grid' parameters]\n\n");
   fprintf(ptr, "nr = %d\nnr_nozzle = %d\nnr_gap = %d\nNrG = %d\n", g->nr,g->nr_nozzle, g->nr_gap, NrG);

   fprintf(ptr, "\n\n['th-grid' parameters]\n\n");
   fprintf(ptr, "nth = %d\n", g->nth);
   fprintf(ptr, "NthG = %d\n", NthG);

   fprintf(ptr, "\n\n['z-grid' parameters]\n\n");
   fprintf(ptr, "nz = %d\nNzG = %d\n", g->nz, NzG);

#else

   fprintf(ptr, "\n\n['r-grid' parameters]\n\n");

#  ifdef r_UNIF_GRID
   fprintf(ptr, "dr: %E ---> %E\n", dR_CYL, g->dr);
#  else
   fprintf(ptr, "dr_center = %E\n", dr_CENTER);
   fprintf(ptr, "r_cd_center ---> %E\n", gc->r_cd_center);
   fprintf(ptr, "**nr_center ---> %d\n", gc->nr_center);
   fprintf(ptr, "*r_mid1: %E ---> %E\n", r_MID1, gc->r_mid1);
   fprintf(ptr, "dr_mid1: %E ---> %E\n", dr_MID1, gc->dr_mid1);
   fprintf(ptr, "dr_mid2 = %E\n", dr_MID2);
   fprintf(ptr, "*r_mid2: %E ---> %E\n", r_MID2, gc->r_mid2);
   fprintf(ptr, "r_cd_mid12 ---> %E\n", gc->r_cd_mid12);
   fprintf(ptr, "**nr_mid12 ---> %d\n", gc->nr_mid12);
   fprintf(ptr, "dr_base: %E ---> %E\n", dr_BASE, gc->dr_base);
   fprintf(ptr, "r_cd_base ---> %E\n", gc->r_cd_base);
   fprintf(ptr, "**nr_base ---> %d\n", gc->nr_base);
   fprintf(ptr, "*r_base = %E\n", r_BASE);
   fprintf(ptr, "dr_wall: %E ---> %E\n", dr_WALL, gc->dr_wall);
   fprintf(ptr, "r_cd_wall ---> %E\n", gc->r_cd_gap);
   fprintf(ptr, "**nr_gap ---> %d\n", g->nr_gap);
#  endif

   fprintf(ptr, "*r_cylinder = %E\n", r_CYL);

   fprintf(ptr, "\n**nr_nozzle ---> %d\n", g->nr_nozzle);
   fprintf(ptr, "**nr_solid ---> %d\n", g->nr_solid);
   fprintf(ptr, "**nr_gap ---> %d\n", g->nr_gap);
   fprintf(ptr, "\n**nr ---> %d\n", g->nr);


   fprintf(ptr, "\n\n['th-grid' parameters]\n\n");

#  ifdef th_UNIF_GRID
   fprintf(ptr, "d_theta:\n\t%E ---> %E (in degrees),\n\t%E ---> %E (in radians)\n", dTHETA, 90*g->dth/acos(0), dTHETA*acos(0)/90, g->dth);

   fprintf(ptr, "**nth = %d\n", g->nth);
#  else
   fprintf(ptr, "ERROR:: in 'print_grid_conf()': incomplete definition for non-uniform grids in thera direction. Exiting the program.\n");
   exit(1);
#  endif

   fprintf(ptr, "\n\n['z-grid' parameters]\n\n");

   fprintf(ptr, "h_cylinder = %E\n", h_CYL);

#  ifdef z_UNIF_GRID
   fprintf(ptr, "dz: %E ---> %E\n", dZ, g->dz);
#  else
   fprintf(ptr, "dz_top = %E\n", dz_TOP);
   fprintf(ptr, "**nz_top ---> %d\n", gc->nz_top);
   fprintf(ptr, "z_cd_top ---> %E\n", gc->z_cd_top);
   fprintf(ptr, "dz_mid2 = %E\n", dz_MID2);
   fprintf(ptr, "*z_mid2: %E ---> %E\n", z_MID2, gc->z_mid2);
   fprintf(ptr, "**nz_mid12 ---> %d\n", gc->nz_mid12);
   fprintf(ptr, "z_cd_mid12 ---> %E\n", gc->z_cd_mid12);
   fprintf(ptr, "dz_mid1 = %E\n", dz_MID1);
   fprintf(ptr, "*z_mid1: %E ---> %E\n", z_MID1, gc->z_mid1);
   fprintf(ptr, "**nz_mid1 ---> %d\n", gc->nz_mid1);
   fprintf(ptr, "z_cd_bot ---> %E\n", gc->z_cd_bot);
   fprintf(ptr, "**nz_unif_bot = %d\n", nz_UNIF_BOT);
   fprintf(ptr, "dz_unif_bot: %E ---> %E\n", dz_UNIF_BOT, gc->dz_unif_bot);
#  endif
   fprintf(ptr, "\n**nz ---> %d\n\n", g->nz);
#endif
   fflush(ptr);


#  ifdef CHECK_CONFIG
   if(ptr != stdout)
       {
        ptr = stdout;
        goto top;
       }
   else{
        fprintf(ptr, "\tAre the parameters reasonable (y/n) ? ");  fflush(ptr);
        if(getchar() != 'y')
           {
            fprintf(ptr, "\nWARNING:: in 'print_grid_conf()': Re-define the grid-configuration parameters in \"scene.h\", re-compine, and then run the program again.\n\n");

            while(getchar() != '\n');
            return -1;
           }
        else while(getchar() != '\n');

        ptr = g->lptr;
       }
#  endif

#  ifdef TRACE_FILE
   fprintf(g->trptr, "...'print_grid_conf()' ends.\n");
#  endif

   return 1;
  }
